package com.cjd.view.radar

import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.view.ViewTreeObserver
import android.widget.FrameLayout
import com.cjd.common.utils.LogUtils
import com.cjd.view.RippleView

import java.util.*
import kotlin.math.abs
import kotlin.math.max


/**
 * @Author chenjidong
 * @email 374122600@qq.com
 * created 2019/9/23
 * description 带波纹文字 在指定区域内 随机显示
 */
class RadarRandomTextView @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attributeSet, defStyleAttr), ViewTreeObserver.OnGlobalLayoutListener {

    private val MAX = 50
    private val IDX_X = 0
    private val IDX_Y = 1
    private val IDX_TXT_LENGTH = 2
    private val IDX_DIS_Y = 3
    private val TEXT_SIZE = 4

    private val random: Random by lazy {
        Random()
    }
    private val vecKeywords: Vector<String> by lazy {
        Vector<String>(MAX)
    }
    private var mWidth: Int = 0
    private var mHeight: Int = 0

    private var mode = RippleView.MODE_OUT
    //字体颜色
    private val fontColor = Color.parseColor("#ffffff")
    //阴影
    private val shadowColor = Color.parseColor("#999999")
    //波纹颜色
    var rippleColor = Color.parseColor("#ff0000")

    private var onRippleOutViewClickListener: OnRippleViewClickListener? = null

    fun setOnRippleViewClickListener(listener: OnRippleViewClickListener) {
        onRippleOutViewClickListener = listener
    }

    interface OnRippleViewClickListener {
        fun onRippleViewClicked(view: View)
    }

    override fun onGlobalLayout() {
        val tmpW = width
        val tmpH = height
        if (mWidth != tmpW || mHeight != tmpH) {
            mWidth = tmpW
            mHeight = tmpH
            LogUtils.d("RandomTextView width = $mWidth; height = $mHeight")
        }
    }

    init {
        viewTreeObserver.addOnGlobalLayoutListener(this)
    }

    fun show() {
        this.removeAllViews()

        if (mWidth > 0 && mHeight > 0 && vecKeywords.size > 0) {
            //找到中心点
            val xCenter = mWidth shr 1
            val yCenter = mHeight shr 1
            //关键字的个数。
            val size = vecKeywords.size
            val xItem = mWidth / (size + 1)
            val yItem = mHeight / (size + 1)
            val listX = LinkedList<Int>()
            val listY = LinkedList<Int>()
            for (i in 0 until size) {
                // 准备随机候选数，分别对应x/y轴位置
                listX.add(i * xItem)
                listY.add(i * yItem + (yItem shr 2))
            }
            val listTxtTop = LinkedList<RippleView>()
            val listTxtBottom = LinkedList<RippleView>()

            for (i in 0 until size) {
                val keyword = vecKeywords[i]
                // 随机颜色
                val ranColor = fontColor
                // 随机位置，糙值
                val xy = randomXY(random, listX, listY, xItem)

                val txtSize = TEXT_SIZE
                // 实例化RippleOutView
                val txt = RippleView(context)
                if (mode == RippleView.MODE_IN) {
                    txt.setMode(RippleView.MODE_IN)
                } else {
                    txt.setMode(RippleView.MODE_OUT)
                }

                txt.setOnClickListener { view ->
                    onRippleOutViewClickListener?.onRippleViewClicked(view)
                }
                txt.text = keyword
                txt.setTextColor(ranColor)
                txt.setRippleColor(rippleColor)
                txt.setTextSize(TypedValue.COMPLEX_UNIT_SP, txtSize.toFloat())
                txt.setShadowLayer(1F, 1F, 1F, shadowColor)
                txt.gravity = Gravity.CENTER
                txt.startRippleAnimation()

                // 获取文本长度
                //Paint paint = txt.getPaint();
                val strWidth = /* (int) Math.ceil(paint.measureText(keyword)) */txt
                    .measuredWidth
                xy[IDX_TXT_LENGTH] = strWidth
                // 第一次修正:修正x坐标
                if (xy[IDX_X] + strWidth > mWidth - xItem/* >> 1 */) {
                    val baseX = mWidth - strWidth
                    // 减少文本右边缘一样的概率
                    xy[IDX_X] = baseX - xItem + random.nextInt(xItem shr 1)
                } else if (xy[IDX_X] == 0) {
                    // 减少文本左边缘一样的概率
                    xy[IDX_X] = max(random.nextInt(xItem), xItem / 3)
                }
                xy[IDX_DIS_Y] = abs(xy[IDX_Y] - yCenter)
                txt.tag = xy
                if (xy[IDX_Y] > yCenter) {
                    listTxtBottom.add(txt)
                } else {
                    listTxtTop.add(txt)
                }
            }

            attach2Screen(listTxtTop, xCenter, yCenter, yItem)
            attach2Screen(listTxtBottom, xCenter, yCenter, yItem)
        }
    }

    /**
     * 修正RippleOutView的Y坐标将将其添加到容器上。
     */
    private fun attach2Screen(
        listTxt: LinkedList<RippleView>, xCenter: Int, yCenter: Int,
        yItem: Int
    ) {
        val size = listTxt.size
        sortXYList(listTxt, size)
        for (i in 0 until size) {
            val txt = listTxt[i]
            val iXY = txt.tag as IntArray
            // 第二次修正:修正y坐标
            val yDistance = iXY[IDX_Y] - yCenter
            // 对于最靠近中心点的，其值不会大于yItem<br/>
            // 对于可以一路下降到中心点的，则该值也是其应调整的大小<br/>
            var yMove = abs(yDistance)
            inner@ for (k in i - 1 downTo 0) {
                val kXY = listTxt[k].tag as IntArray
                val startX = kXY[IDX_X]
                val endX = startX + kXY[IDX_TXT_LENGTH]
                // y轴以中心点为分隔线，在同一侧
                if (yDistance * (kXY[IDX_Y] - yCenter) > 0) {
                    if (isXMixed(startX, endX, iXY[IDX_X], iXY[IDX_X] + iXY[IDX_TXT_LENGTH])) {
                        val tmpMove = abs(iXY[IDX_Y] - kXY[IDX_Y])
                        if (tmpMove > yItem) {
                            yMove = tmpMove
                        } else if (yMove > 0) {
                            // 取消默认值。
                            yMove = 0
                        }
                        break@inner
                    }
                }
            }

            if (yMove > yItem) {
                val maxMove = yMove - yItem
                val randomMove = random.nextInt(maxMove)
                val realMove = max(randomMove, maxMove shr 1) * yDistance / Math.abs(yDistance)
                iXY[IDX_Y] = iXY[IDX_Y] - realMove
                iXY[IDX_DIS_Y] = abs(iXY[IDX_Y] - yCenter)
                // 已经调整过前i个需要再次排序
                sortXYList(listTxt, i + 1)
            }
            val layParams = LayoutParams(
                /* FrameLayout.LayoutParams.WRAP_CONTENT */100,
                /* FrameLayout.LayoutParams.WRAP_CONTENT */100
            )
            layParams.gravity = Gravity.LEFT or Gravity.TOP
            layParams.leftMargin = iXY[IDX_X]
            layParams.topMargin = iXY[IDX_Y]
            addView(txt, layParams)
        }
    }

    private fun randomXY(
        ran: Random, listX: LinkedList<Int>,
        listY: LinkedList<Int>, xItem: Int
    ): IntArray {
        val arr = IntArray(4)
        arr[IDX_X] = listX.removeAt(ran.nextInt(listX.size))
        arr[IDX_Y] = listY.removeAt(ran.nextInt(listY.size))
        return arr
    }

    /**
     * A线段与B线段所代表的直线在X轴映射上是否有交集。
     */
    private fun isXMixed(startA: Int, endA: Int, startB: Int, endB: Int): Boolean {
        var result = false
        if (startB >= startA && startB <= endA) {
            result = true
        } else if (endB >= startA && endB <= endA) {
            result = true
        } else if (startA >= startB && startA <= endB) {
            result = true
        } else if (endA >= startB && endA <= endB) {
            result = true
        }
        return result
    }

    /**
     * 根据与中心点的距离由近到远进行冒泡排序。
     *
     * @param endIdx  起始位置。
     * @param listTxt 待排序的数组。
     */
    private fun sortXYList(listTxt: LinkedList<RippleView>, endIdx: Int) {
        for (i in 0 until endIdx) {
            for (k in i + 1 until endIdx) {
                if ((listTxt[k].tag as IntArray)[IDX_DIS_Y] < (listTxt[i].tag as IntArray)[IDX_DIS_Y]) {
                    val iTmp = listTxt[i]
                    val kTmp = listTxt[k]
                    listTxt[i] = kTmp
                    listTxt[k] = iTmp
                }
            }
        }
    }

    /**
     * 添加RippleOutView的内容
     *
     * @param keyword
     */
    fun addKeyword(keyword: String) {
        if (vecKeywords.size < MAX) {
            if (!vecKeywords.contains(keyword))
                vecKeywords.add(keyword)
        }
    }

    fun getKeywords(): Vector<String> {
        return vecKeywords
    }

    fun removeKeyword(keyword: String) {
        if (vecKeywords.contains(keyword)) {
            vecKeywords.remove(keyword)
        }
    }
}